//
//  UILabel+YHCount.m
//  YHKit
//
//  Created by 林宁宁 on 2021/5/14.
//

#import "UILabel+YHCount.h"
#import <objc/runtime.h>
#import <YHConstant/YHConstant+Method.h>

@interface YHLabelCountingConfig()

@property (nonatomic, strong) CADisplayLink * runTimer;

@property (assign, nonatomic) CGFloat progress;//进度
@property (assign, nonatomic) CGFloat lastUpdate;//最新一次运动的时间戳
@property (assign, nonatomic) CGFloat totalTime;//需要运动的总时间

/// 最终值
@property (assign, nonatomic) CGFloat endValue;
/// 初始开始位置 也是当前的值
@property (assign, nonatomic) CGFloat startValue;
/// 目标值跟初始值之间的差值
@property (assign, nonatomic) CGFloat difference;

@end

@implementation YHLabelCountingConfig

-(void)clean{
    self.attributedFormatBlock = nil;
    self.formatBlock = nil;
    self.startValueBock = nil;
    self.completionBlock = nil;
}

@end



@implementation UILabel (Counting)


-(YHLabelCountingConfig *)yh_countingConfig{
    YHLabelCountingConfig * config = objc_getAssociatedObject(self, @selector(yh_countingConfig));
    if(!config){
        config = [YHLabelCountingConfig new];
        config.format = @"%d";
        
        objc_setAssociatedObject(self, @selector(yh_countingConfig), config, OBJC_ASSOCIATION_RETAIN);
    }
    return config;
}

-(void)yh_countingTo:(CGFloat)endValue{

    [self timerStop];
    
    self.yh_countingConfig.endValue = endValue;
    if(self.yh_countingConfig.startValueBock){
        self.yh_countingConfig.startValue = self.yh_countingConfig.startValueBock();
    }
    
    [self timerBegin];
}

- (void)yh_countingWithoutAnimationTo:(CGFloat)endValue{

    [self timerStop];
    
    self.yh_countingConfig.endValue = endValue;
    
    [self updateTextWithValue:endValue];
    
    [self runFinish];
}

- (void)timerBegin{
    [self timerStop];

    //距离 目标的差值
    self.yh_countingConfig.difference = self.yh_countingConfig.endValue - self.yh_countingConfig.startValue;
    
    NSLog(@"difference = %f",self.yh_countingConfig.difference);
    
    self.yh_countingConfig.totalTime = ABS(self.yh_countingConfig.difference)*0.08;
    self.yh_countingConfig.totalTime = MAX(self.yh_countingConfig.totalTime, 0.2);
    self.yh_countingConfig.totalTime = MIN(self.yh_countingConfig.totalTime, 1.3);
        
    NSLog(@"totalTime = %f",self.yh_countingConfig.totalTime);
    
    self.yh_countingConfig.lastUpdate = [NSDate timeIntervalSinceReferenceDate];
    
    CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(runEvent)];
    [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];
    self.yh_countingConfig.runTimer = timer;
}

- (void)timerStop{
    
    [self.yh_countingConfig.runTimer invalidate];
    self.yh_countingConfig.runTimer = nil;
}

- (void)runEvent{
    
    NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
    self.yh_countingConfig.progress += now - self.yh_countingConfig.lastUpdate;
    self.yh_countingConfig.lastUpdate = now;
    
    CGFloat curProgress = 0;
    if (self.yh_countingConfig.progress >= self.yh_countingConfig.totalTime) {
        curProgress = 1;
    }else{
        CGFloat percent = self.yh_countingConfig.progress/self.yh_countingConfig.totalTime;
        switch (self.yh_countingConfig.method) {
            case YHAnimationCountingMethod_EaseIn:{
                curProgress = YHAnimation_EaseIn(percent);
            }
                break;
            case YHAnimationCountingMethod_Linear:{
                curProgress = YHAnimation_Linear(percent);
            }
                break;
            case YHAnimationCountingMethod_EaseOut:{
                curProgress = YHAnimation_EaseOut(percent);
            }
                break;
            case YHAnimationCountingMethod_EaseInOut:{
                curProgress = YHAnimation_EaseInOut(percent);
            }
                break;
            case YHAnimationCountingMethod_EaseInBounce:{
                curProgress = YHAnimation_EaseInBounce(percent);
            }
                break;
            case YHAnimationCountingMethod_EaseOutBounce:{
                curProgress = YHAnimation_EaseOutBounce(percent);
            }
                break;
                
            default:
                curProgress = YHAnimation_EaseOut(percent);
                break;
        }
    }
    
    CGFloat stepValue = self.yh_countingConfig.difference*curProgress;
    stepValue = self.yh_countingConfig.startValue + stepValue;
        
    [self updateTextWithValue:stepValue];
    
//    NSLog(@"")
//    NSLog(@"%f === %zd",curProgress,stepProgress);
    
    if(stepValue == self.yh_countingConfig.endValue){
        //已走完总步数
        [self runFinish];
    }
}

- (void)updateTextWithValue:(CGFloat)stepValue{
        
    YHLabelCountingConfig * config = self.yh_countingConfig;
    
    if (config.attributedFormatBlock) {
        self.attributedText = config.attributedFormatBlock(stepValue);
    }
    else if(config.formatBlock){
        self.text = config.formatBlock(stepValue);
    }else{
        // check if counting with ints - cast to int
        // regex based on IEEE printf specification: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
        if([config.format rangeOfString:@"%[^fega]*[diouxc]" options:NSRegularExpressionSearch|NSCaseInsensitiveSearch].location != NSNotFound)
        {
            stepValue = (NSInteger)(stepValue * 100);
            stepValue = stepValue * 0.01;
            self.text = [NSString stringWithFormat:config.format,stepValue];
        }else{
            self.text = [NSString stringWithFormat:config.format,stepValue];
        }
    }
}

- (void)runFinish{
    
    NSLog(@"数字跳动完成 定时器停止");
    
    [self timerStop];
    
    self.yh_countingConfig.progress = 0;
            
    self.yh_countingConfig.startValue = self.yh_countingConfig.endValue;
        
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if(self.yh_countingConfig.completionBlock){
            self.yh_countingConfig.completionBlock();
        }
    });
}


@end
